﻿using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace zijian666.DI;


/// <summary>
/// 自定义服务提供程序, 提供在未 <seealso cref="ServiceCollectionContainerBuilderExtensions.BuildServiceProvider(IServiceCollection)"/> 之前需要使用 <seealso cref="IServiceProvider"/> 的场景
/// </summary>
internal class ServiceProviderProxy : IServiceProvider
{
    private readonly List<object> _args;
    private readonly IServiceProvider? _provider;
    private ILogger? _logger;

    public ILogger? Logger => _logger ??= (GetService(typeof(ILoggerFactory)) as ILoggerFactory)?.CreateLogger<Launcher>();

    public ServiceProviderProxy(IServiceProvider? provider = null, IEnumerable<object>? args = null)
    {
        _provider = provider;
        _args = [];

        // 枚举动态参数和单例服务
        if (args is not null)
        {
            foreach (var arg in args)
            {
                AddService(arg);
            }
        }
    }

    private IEnumerable<object> GetServices(Type type)
    {
        if (_args.Count <= 0)
        {
            yield break;
        }
        for (int i = 0; i < _args.Count; i++)
        {
            var arg = _args[i];
            if (type.IsInstanceOfType(arg))
            {
                yield return arg;
            }
            if (arg is ServiceDescriptor descriptor && type.IsAssignableFrom(descriptor.ServiceType))
            {
                var value = descriptor.GetService(this);
                if (value is not null)
                {
                    _args[i] = value;
                    yield return value;
                }
            }
        }
    }

    public object? GetService(Type type)
    {
        foreach (var arg in GetServices(type))
        {
            return arg;
        }

        if (_provider is not null)
        {
            if (type.IsInstanceOfType(_provider))
            {
                return _provider;
            }
            var service = _provider.GetService(type);
            if (service is not null)
            {
                return service;
            }
            foreach (var interfaceType in type.GetInterfaces())
            {
                service = _provider.GetService(type);
                if (service is not null)
                {
                    return service;
                }
            }
        }
        if (_args.Count > 0)
        {
            var serviceType = type.GetInterfaces().FirstOrDefault(x => x.IsGenericType && !x.IsGenericTypeDefinition && x.GetGenericTypeDefinition() == typeof(IEnumerable<>));
            if (serviceType is not null)
            {
                var listType = typeof(ICollection<>).MakeGenericType(serviceType);
                if (listType.IsAssignableTo(type))
                {
                    var list = (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(serviceType))!;

                    foreach (var arg in GetServices(serviceType))
                    {
                        list.Add(arg);
                    }
                    return list;
                }
                if (type.IsAssignableTo(listType))
                {
                    try
                    {
                        var list = Activator.CreateInstance(type)!;
                        var add = listType.GetMethod("Add")!;
                        var p = new object[1];
                        foreach (var arg in GetServices(serviceType))
                        {
                            p[0] = arg;
                            add.Invoke(list, p);
                        }
                        return list;

                    }
                    catch (Exception e)
                    {
                        Logger?.LogError(e, "获取指定类型服务时发生异常");
                    }
                }
            }
        }
        return null;
    }

    /// <summary>
    /// 添加单例服务
    /// </summary>
    public ServiceProviderProxy AddService(object? arg)
    {
        if (arg is not null)
        {
            _args.Add(arg);
        }
        return this;
    }

    /// <summary>
    /// 添加单例服务
    /// </summary>
    public ServiceProviderProxy AddServices(IEnumerable<object>? args)
    {
        if (args is not null)
        {
            _args.AddRange(args.Where(x => x is not null).Distinct());
        }
        return this;
    }
}
